home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr49
/
121_01.zip
/
TEL.C
< prev
next >
Wrap
Text File
|
1993-06-01
|
23KB
|
1,118 lines
/*
HEADER: CUG 121.??;
TITLE: tel - dumb terminal + file xfer;
VERSION: 1.0;
DATE: 01/06/86;
DESCRIPTION: "Tel is a considerably modified version of Telnet v2.3, as
distributed with v1.46 of the BDS C compiler. The following
features have been added: multiple files may be transmitted or
received by one command, directories may be listed, and the
quit command hangs up a hayes smartmodem. To accommodate
these changes, some of the command names have been changed.
This program uses a modem to emulate a dumb terminal.
Incoming data may be buffered in memory and written to disk,
data may be transmitted from disk to the modem, or files may
be formally transferred in a "checksum" mode with automatic
handshaking and buffering.";
KEYWORDS: terminal, modem, emulate, file transfer;
SYSTEM: CP/M;
FILENAME: TEL.C;
WARNINGS: "Requires local.c and files.c for link.
The checksum file transfer does not follow the XMODEM
protocol.
Variable baud rate support is present, but commented out
(hardware-specific coding would be required to implement it).
Tel assumes that the CP/M console is much faster than the
modem (e.g. a 1200+ baud console with a 300 baud modem).";
SEE-ALSO: CALL.C, TELNET.C, TL370.C;
AUTHORS: Leor Zolman, Leo Kenen, Cal Thixton, Mike W. Meyer;
COMPILERS: BDS-C 1.50;
*/
#include <bdscio.h> /* System, h'ware constants */
#include <hardware.h>
#ifdef MULL /* muellers version if MULL is defined. */
#define TITLE "Mulltel version 1.5 12/3/80 tj"
#define INITB 3 /* 1200 baud initially */
#define SSPECIAL '\\' /* escape character initially */
#else
#define TITLE "Telnet version 3.0-Intersystems 10/25/80 (mwm)\n"
#define SSPECIAL 29 /* Initial escape character ^] */
#define INITB 5 /* 4800 baud initially. See setbaud() */
#endif
#define SELDSK 14 /* change logged in disk */
#define DIRFRST 17 /* search for first occurance of a file */
#define DIRNEXT 18 /* search for next occurance of a file */
#define CURRDSK 25 /* return currently logged in disk */
#define maxfiles 64 /* maximun # of file to send as once */
/*
The following #defines need not be changed:
*/
#define ACK 0x06 /* Ascii ACK for handshaking */
#define NAK 0x15
#define EOT 0x04 /* End of transmission */
#define ETX 0x03 /* Abort Transmission */
#define STX 0x02 /* Beginning of next filename to send */
#define NUL 0x0 /* end of file name */
#define PHA 0xfd /* for phase checking */
#define CR 0x0d /* carriage return */
#define LF 0x0a /* line feed */
#define NL '\n' /* god knows, compiler dependent! */
/*
File Control Block structure
*/
struct FCB {
char entry, /* entry type. assumed 0 */
name[8], /* file name */
type[3], /* file type */
extent, /* which entention is this one? */
na,naa, /* not used (??) */
count, /* record count */
map[16], /* disk allocation map */
next; /* next record to read */
};
/*
External variable declarations:
*/
char SPECIAL; /* current SPECIAL or escape character */
char rflag; /* receiving file open flag */
char tflag; /* transmitting file open flag */
char chflag; /* checksumming enabled flag */
char cflag; /* text-collection enabled flag */
char pflag; /* pausing flag */
char spflag; /* stripping parity bit flag */
char nflag; /* recognizing nulls flag */
char fflag; /* true if changing CR-LF's into
just CR when transmitting */
char lastc; /* last char transmitted */
char dodflag; /* true if displaying outging data */
char didflag; /* true if displaying incoming data */
char hdflag; /* true if effectively working in half-duplex */
char hd_sav; /* save flag when transmitting or receiving */
char abortf; /* true when file I/O aborted */
char rbuf[BUFSIZ]; /* file I/O buffer for incoming data file */
char tbuf[SECSIZ]; /* sector buffer for file being transmitted */
char tmp[20]; /* tempory holding place for file name */
char rname[20]; /* name of receiving file */
char tname[20]; /* name of transmitting file */
int rfd, tfd; /* file descriptors */
char *cptr; /* pointer to free space in buf */
unsigned free; /* number of bytes free in buf */
int bcount; /* counts bytes in current block when checksumming */
int scount; /* Number of sectors sent/received */
int checksum; /* the checksum value itself */
char timoutf; /* 1 if time-out happens while waiting for modem data*/
char *i; /* odd-job char pointer */
int dod_sav, did_sav; /* scratch variables */
unsigned bufspace; /* # of bytes available for collection buffer in ram */
char toupper(); /* This makes for better code */
char fcb[34]; /* file control block */
struct { /* so i can't use initializers */
char rate[5], /* readable baud rate */
hex;
} bauds [7];
char current; /* current baud rate being used */
char files[maxfiles][17]; /* files to send */
char leftover; /* number of file to send */
char thisdisk; /* currently logged in disk */
char *buf; /* text collection pointer; will
point to the location just after itself */
/*
place for main.c
*/
main()
{
char c, c2;
int n;
init();
while(1) {
if (abortf) {
if (rflag)
rclose();
if (tflag)
tabort();
reset();
abortf = 0;
}
if (tflag && xmit()) {
printf("\nTransmission complete.\n");
close(tfd);
reset();
}
if (abortf)
continue;
if (miready()) {
c = c2 = getmod();
if (spflag)
c &= 0x7f;
if (tflag && (c == ETX)) {
printf("Receiver has aborted;\n");
abortf = 1;
continue;
}
if (didflag && (c || nflag) && (c != CPMEOF))
display(c);
if (cflag && !pflag) {
if (c || nflag)
if (!free) {
printf("**BUFFER FULL**\007\007");
rdump(0);
}
else {
*cptr++ = c;
free--;
}
if (chflag) {
checksum += c2;
bcount++;
if (bcount == SECSIZ) {
bcount = 0;
outmod(checksum >> 8);
outmod(checksum);
checksum = 0;
c = getmod();
if(c == STX) {
getname(tmp);
rdump(0);
rclose();
scount=0;
strcpy(rname,tmp);
if(opento()) {
outmod(ETX);
abortf=1;
}
outmod(PHA);
}
else if (c == EOT) {
rdump(0);
rclose();
reset();
printf("\n%s received OK\n",rname);
}
else if (c == ACK) {
if (cptr > buf+1000)
rdump(0);
if (!didflag)
printf("-%d",++scount);
outmod(PHA);
}
else {
cptr -= SECSIZ;
free += SECSIZ;
printf("\nChecksum error. Retrying <%d>\n",scount+1);
outmod(PHA);
timoutf = 0;
}
}
}
}
}
if (kbready()) {
c = getch();
if (c != SPECIAL) {
if (pflag || (!tflag && !(rflag && chflag))) {
outmod(c);
if (dodflag)
display(c);
}
}
else special();
}
}
}
/*
place for special.c
*/
/*
Handle special Telnet command:
*/
special()
{
char c;
int nn,n;
printf("\n?: ");
if ( (c = getchar()) != NL) printf("...");
if(c==SPECIAL) {
outmod(SPECIAL);
printf("Current Escape 0x%02x sent", SPECIAL) ;
}
else switch (toupper(c)) {
case 'E' :
printf("Current Escape Character: 0x%02x\n",SPECIAL);
printf("Enter New Escape Character: ");
SPECIAL=getchar();
putchar(NL);
break;
case '7':
spflag = ask("Strip parity");
break;
case 'B':
dobauds();
break;
case 'N':
nflag = ask("Recognize incoming nulls");
break;
case 'F':
fflag = ask("Transmit CR-LF pairs as CR only");
break;
case 'H':
if (rflag || tflag) {
printf("Must abort transfer first\n");
break;
}
hd_sav = hdflag = ask ("Half Duplex");
reset();
break;
case 'Z':
puts(CLEARS) ;
break;
case 'P':
if (pflag)
printf("Already pausing");
else if (!(tflag || rflag))
printf("Not transmitting or receiving");
else {
pflag = 1;
dod_sav = dodflag;
did_sav = didflag;
dodflag = !hdflag;
didflag = 1;
printf("Pausing from %s", tflag ?
"transmission" : "collection");
}
putchar(NL);
break;
case 'R':
if (!pflag)
printf("Not pausing");
else {
pflag = 0;
dodflag = dod_sav;
didflag = did_sav;
printf("%s now enabled again.", tflag ?
"transmission" : "collection");
}
putchar(NL);
break;
case 'K':
printf("Text buffer: ZAPPED!");
free = bufspace;
cptr = buf;
putchar(NL);
break;
case 'V':
if (rflag) {
putchar(NL);
i = buf;
while (i < cptr && !kbready())
putchar(*i++);
if(i<cptr)
getchar();
printf("\n%u bytes free",free);
}
else
printf("No receiving file open");
putchar(NL);
break;
case 'D':
if (rflag)
rdump(1);
else
printf("No output file");
putchar(NL);
break;
case 'C':
if (rflag)
rclose();
else
printf("No output file");
putchar(NL);
break;
case 'Q': hangup() ; /* hangup the modem */
case 'X':
printf("Quit\n");
if (tflag) tabort();
if (rflag) rclose();
exit();
case 'A':
if (tflag || rflag) {
if (chflag) outmod(ETX);
abortf = 1;
break;
}
printf("No transfer to abort.\n");
putchar(NL);
break;
case 'O':
if (rflag)
rclose();
if (tflag)
tabort();
rflag = 1;
if (!askstuff()) {
reset();
return;
}
cptr = buf;
free = bufspace;
rflag = cflag = 1;
scount = pflag = checksum = bcount = 0;
if (chflag) {
printf("Trying to link...");
do {
c = getmod();
if (abortf) {
printf("aborting...\n");
reset();
return;
}
timoutf = 0;
} while (c & 0x7f);
printf("linked.\n");
outmod(0);
if(getmod() != STX) {
printf("STX ERROR\n");
reset();
return;
}
getname(rname);
if(opento()) {
outmod(ETX);
abortf=1;
}
outmod(PHA);
}
break;
case 'T':
printf("Transmit\n");
if (tflag)
tabort();
if (rflag)
rclose();
printf("\nEnter file names to send:\n");
leftover=0;
while(1) {
++leftover;
printf("%d) File name: ",leftover);
gets(files[leftover-1]);
n=leftover;
if(nameok()) /* return 1 too many or end */
break;
for(nn=n;nn<=leftover;nn++)
printf("File %d: %s\n",nn,files[nn-1]);
}
printf("%d Files to send\n",--leftover);
if (!leftover || !askstuff()) {
reset();
break;
}
strcpy(tname,files[leftover-1]);
tflag = 1;
if(leftover && ((tfd=open(tname,0))==ERROR)) {
printf("Fatal error: Cannot open %s\n",tname);
reset();
abortf=1;
break;
}
scount = pflag = checksum = bcount = 0;
if (read(tfd,tbuf,1) <=0) {
printf("Read error from %s\n",tname);
reset();
abortf = 1;
break;
}
if (chflag) {
printf("Trying to link...");
while (1) {
outmod(0);
for (n=0; n<5000; n++)
if (miready()) {
if(!(getmod()&0x7f)){
printf("linked.\n");
outmod(STX);
sendname(tname);
printf("\nSending %d: %s\n",leftover,tname);
if(getmod()!=PHA) {
printf("ERROR\n");
abortf=1;
}
return;
}
}
else
if (kbabort()) {
printf("aborting.\n");
return;
}
}
}
break;
case 'S':
dostat();
break;
case 'L':
if(rflag || tflag) {
printf("Cannot list disk while %s data\n",
(rflag)?"receiving":"transmitting");
break;
}
dir();
break;
case 'G':
if(rflag || tflag) {
printf("Cannot change disk while %s data\n",
(rflag)?"receiving":"transmitting");
break;
}
printf("Newly logged-in Disk: %c:\n",togdisk());
break;
default:
prcoms();
}
}
/*
Print out legal Telnet commands:
*/
prcoms()
{
puts(CLEARS) ;
printf("BDS Telnet commands are:\n");
printf("?: This listing\n");
printf("0x%02x: send 0x%02x\n",SPECIAL,SPECIAL);
printf("7: Select policy regarding Parity bits\n");
printf("a: Abort transfer of file\n");
printf("b: Select baud rate\n");
printf("c: Close input file (after dumping buffer)\n");
printf("d: Dump (append) text buffer to output file\n");
printf("e: Change ESCAPE Character\n");
printf("f: Select whether to transmit CR-LF as just CR\n");
printf("g: Go (login) to other disk\n");
printf("h: Set Half/full duplex mode\n");
printf("k: Kill (erase) contents of input buffer\n");
printf("l: List files on disks\n");
printf("n: Accept or ignore Nulls\n");
printf("o: Open input file, start collection\n");
printf("p: Pause (suspend collection or transmission)\n");
printf("q: Dump & close input file (if open) and Quit to CP/M\n");
printf("r: Resume after pausing\n");
printf("s: Display Status\n");
printf("t: Transmit a file\n");
printf("v: View contents of input buffer\n");
printf("x: eXit to CP/M, don't hangup the modem\n") ;
printf("z: Clear screen\n");
}
/*
Print opening message and initialize program:
*/
init()
{
printf(TITLE);
_allocp = NULL; /* initialize allocation pointer */
hdflag = hd_sav = lastc = timoutf = cflag = 0;
nflag = pflag = abortf = fflag = 0;
spflag=1;
SPECIAL=SSPECIAL; /* initial escape character */
buf = &buf + 1;
bufspace = buf + 500 - topofmem();/* compute space available */
bufspace = -bufspace; /* for text collection buf */
reset();
/* initbaud();
setbaud(current=INITB); /* defualt baud rate: 4800 */
leave this stuff out, for now... */
}
/*
hangup a hayes smartmodem
*/
hangup() {
sleep(20) ; /* a nice long wait */
hayesput("...") ; /* get it's attention */
hayesput("AT H\r") ; /* tell it to hang up */
} /* and we is through */
/*
set baud rates
*/
setbaud(r)
char r;
{
/*
outp(CTCPORT,SETBAUD); /* set baud rate */
outp(CTCPORT,bauds[r].hex);
are you kidding */
}
initbaud()
{
strcpy(bauds[0].rate,"110"); bauds[0].hex=0x57;
strcpy(bauds[1].rate,"300"); bauds[1].hex=0x20;
strcpy(bauds[2].rate,"600"); bauds[2].hex=0x10;
strcpy(bauds[3].rate,"1200"); bauds[3].hex=0x8;
strcpy(bauds[4].rate,"2400"); bauds[4].hex=0x4;
strcpy(bauds[5].rate,"4800"); bauds[5].hex=0x2;
strcpy(bauds[6].rate,"9600"); bauds[6].hex=0x1;
}
dobauds()
{
char n;
puts(CLEARS) ;
printf("Current Baud rate is %s\n\n",
bauds[current].rate);
for(n=0; n<7; n++)
printf("%c: %s\n",n+0x41,bauds[n].rate);
printf("\nWhich rate? ");
n=toupper(getchar())-0x41;
if(n>=0 && n<7)
setbaud(current=n);
putchar(NL);
}
/*
rest of tel.c stuff
*/
/*
Get all the info pertinent to a file transfer; i.e,
whether or not the file is text (and needs parity
stripped, nulls ignored, echoing to console, etc.),
whether or not checksumming and handshaking are
required (they always go together), and make sure
the user is in full duplex mode.
*/
askstuff()
{
chflag = ask("Handshaking & checksumming:");
if (!chflag && ask("Is this a text file")) {
nflag = 0;
spflag = didflag = 1;
dodflag = !hdflag;
}
else {
spflag = didflag = dodflag = 0;
nflag = 1;
}
if(!chflag && rflag) {
printf("Input file? ");
gets(rname);
if(!strlen(rname) || opento())
return(0);
}
hd_sav=hdflag;
hdflag = 0;
return(ask("\nOK...type y to begin, n to abort:"));
}
/*
Routine to print out a string and return true
if the user responds positively
*/
ask(s)
char *s;
{
char c;
while (1) {
printf("%s (y/n)? ",s);
switch(c=toupper(getchar())) {
case 'Y': printf("es\n");
case '1' : return 1;
case 'N' : printf("o\n");
case '0' :
case NL : return 0;
default : printf("???\n");
break;
}
}
}
/*
Print out status of Telnet
*/
dostat()
{
putchar(NL);
if (rflag) {
printf("Output file = %s\n",rname);
printf("\nText collection: ");
if (cflag)
if (pflag) printf("on, but pausing\n");
else printf("on\n");
else printf("off\n");
}
else printf("No output file\n");
printf("Text buffer has %u bytes free\n",free);
if (tflag) {
printf("Transmitting: %s ",tname);
if (pflag)
printf("(but pausing)");
putchar(NL);
}
else printf("Not transmitting any file\n");
printf("Current Escape Character: 0x%02x\n",SPECIAL);
printf("Incoming nulls are being %s\n",nflag?"collected" : "ignored");
printf("Parity bits are being %s\n",spflag ?"stripped" : "preserved");
printf("%s\n",hdflag ? "Half-Duplex" : "Full-Duplex");
printf("Current Baud rates: Main: %s Aux: %s\n",
bauds[current&0xf],bauds[current>>4]);
printf("Disk: %c:\n",disk());
}
/*
Routine to dump contents of the memory text buffer
to the output file and clear the buffer for more
data:
*/
rdump(n)
{
for (i=buf; i<cptr; i++)
putc(*i,rbuf);
cptr = buf;
free = bufspace;
if (n)
printf("\nBuffer written. ");
}
/*
Routine to dump and close the output file:
*/
rclose()
{
rdump(1);
printf(" Closing %s ",rname);
if (!chflag)
putc(CPMEOF,rbuf);
fflush(rbuf);
close(rfd);
putchar(NL);
}
/*
Routine to reset telnet
*/
reset()
{
leftover = scount = timoutf = rflag = tflag = chflag = cflag = 0;
didflag = spflag = 1;
dodflag = !hdflag;
hdflag=hd_sav;
}
/*
Get a byte from the modem:
*/
getmod()
{
char c;
unsigned n;
if (timoutf)
return;
for (n=20000; !miready() && n; n--)
if (kbabort())
return;
if (!n) {
timoutf = 1;
return(1);
}
c = mgetc();
return(c);
}
/*
Output a byte to the modem:
*/
outmod(c)
char c;
{
while (!moready())
if (kbabort())
return;
mputc(c);
}
/*
return true if a key has been pressed, else 0
*/
kbready()
{
return bios(2);
}
/*
Get a character from the keyboard:
(Uses a direct BIOS instead of going through
the BDOS. By naming this the same as the library
version of "getchar", we insure that THIS version
is used by things like "gets" instead of the library
version.)
*/
getchar()
{
char c;
c = getch();
if (c == CR)
c = NL;
putchar(c);
return c;
}
getch()
{
return bios(3);
}
/*
Return true if keyboard hit and SPECIAL typed:
*/
kbabort()
{
if (kbready() && getch() == SPECIAL) {
abortf = 1;
return 1;
}
return 0;
}
/*
Write a character to the console.
*/
putchar(c)
char c;
{
if (c == NL)
putch2(CR);
putch2(c);
}
putch2(c)
char c;
{
bios(4,c);
}
/*
Write character to console display
*/
display(c)
char c;
{
putch2(c&0x7f);
}
/*
Read a sector of the transmission file:
*/
read1()
{
int i;
i = read(tfd, tbuf, 1);
if ( i == ERROR) {
printf("\nRead error from %s; Aborting.\n",tname);
tabort();
}
return(i);
}
tabort()
{
if (chflag)
while (bcount++ != 133)
outmod(ETX);
printf("\nTransmission of %s aborted.\n",tname);
close(tfd);
reset();
}
/*
create receiving file. if it already exists, change type name
and try again.
*/
opento()
{
char c;
c=1;
printf("Creating %s...",rname);
while((rfd=open(rname,0)) != ERROR) {
close(rfd);
addtype(rname,c++);
printf("File exists..Trying %s...",rname);
}
if ((rfd=fcreat(rname,rbuf)) == ERROR) {
printf("Cannot create %s\n",rname);
reset();
return(1);
}
return(0);
}
/*
add sub name to file name if file already exsists
*/
addtype(f,c)
char *f,c;
{
char d,o[4];
for(d=0;f[d] && f[d]!='.';d++);
sprintf(o,"%-3d",c);
if(!f[d]) {
f[d]='.';
f[d+1]=0;
}
else
f[d+1]=0;
strcat(f,o);
}
/*
send file name being transmitted
*/
sendname(f)
char *f;
{
char c;
for(c=0; *f && c<12; c++)
outmod(*(f++));
outmod(NUL);
}
/*
get file name being sent
*/
getname(a)
char *a;
{
char d,c,*q;
q=a;
for(d=0; (c=getmod()) && d<12; d++)
*(q++)=c;
*q=0;
}
/*
display files on currently logged in disk
*/
dir()
{
char f;
struct FCB fcb;
putchar(NL);
bdos(SELDSK,thisdisk&0x0f);
strcpy(files[0],"????????.???");
leftover=1;
nameok();
for(f=0;f<leftover;f++)
printf("%-12s%c",files[f],((f+1)%6)?' ':'\n');
putchar(NL);
}
/*
returns disk name of currently logged in disk
*/
disk()
{
return("AB"[bdos(CURRDSK,0)&0x0f]);
}
/*
change currently logged-in disk to other disk
*/
togdisk()
{
bdos(SELDSK,(thisdisk=((thisdisk)?0:1)));
return(disk());
}
/*
check to see if this file is in directory
*/
nameok()
{
char f,c,o[20];
struct FCB fcb;
if(!strlen(files[leftover-1]))
return(1);
setfcb(fcb,files[leftover-1]);
leftover--;
for(f=DIRFRST;(c=bdos(f,&fcb))!=255 && leftover<maxfiles;f=DIRNEXT) {
pickout(0x80+(c*32),o);
strcpy(files[leftover++],o);
}
return((leftover<maxfiles)?0:1);
}
xmit()
{
int incheck;
int n;
char c;
if (pflag || !moready())
return 0;
c = tbuf[bcount++];
checksum += c;
if ((!(spflag && (c&0x7f)==CPMEOF && !chflag)) &&
(!(!chflag && c==NL && lastc==CR && !nflag && fflag)))
outmod(c);
lastc = c;
if (dodflag)
display(c);
if (bcount != SECSIZ)
return 0;
bcount = 0;
if (!chflag)
return(!read1());
incheck = (getmod() << 8) + getmod();
if (incheck != checksum) {
for (n=0; n<20000; n++); /* let line settle down */
printf("\nError. Resending sector %d...\n",scount+1);
outmod(NAK);
}
else if (read1()) {
if (!dodflag)
printf(".%d",++scount);
outmod(ACK);
}
else if(leftover) {
close(tfd);
--leftover;
strcpy(tname,files[leftover-1]);
while(leftover && ((tfd=open(tname,0))==ERROR)){
if(!dodflag)
printf("Unknown error: Can't open %s\n",tname);
leftover=0;
}
if (!leftover) {
reset();
putchar(NL);
outmod(EOT);
return(1);
}
if(!dodflag)
printf("\nSending %d: %s\n",leftover,tname);
outmod(STX);
sendname(tname);
scount = pflag = checksum = bcount = 0;
if (read(tfd,tbuf,1) <=0) {
printf("Read error from %s\n",tname);
reset();
abortf = 1;
return;
}
}
else {
outmod(EOT);
return(1);
}
checksum = 0;
if (getmod() != PHA) {
printf("\nPhase error; aborting...");
abortf = 1;
}
return 0;
}